import { observe } from "./observe/index";
import Watcher from "./observe/watcher";

export function initState(vm) {
  const options = vm.$options;

  // props->data
  if (options.data) {
    initData(vm);
  }
  if (options.watch) {
    initWatch(vm);
  }
}

function proxy(vm, source, key) {
  Object.defineProperty(vm, key, {
    get() {
      return vm[source][key];
    },
    set(newValue) {
      vm[source][key] = newValue;
    }
  })
}

function initData(vm) {
  let data = vm.$options.data;

  // 用户的 data 可能是函数和对象
  data = vm._data = typeof data === "function" ? data.call(vm) : data || {};

  // 为了方便用户通过实例 vm.xxx 直接获取到属性，而不是 vm._data.xxx 
  for (const key in data) {
    proxy(vm, "_data", key);
  }

  // defineProperty 来对属性劫持
  observe(data);
}

function initWatch(vm) {
  const watch = vm.$options.watch;
  // console.log('initWatch', watch)
  for (const key in watch) {
    const handler = watch[key];
    createWatcher(vm, key, handler);
  }
}

function createWatcher(vm, key, handler) {
  let options;
  // 这里处理多种兼容写法
  if (typeof handler === 'object' && handler != null) {
    options = handler;
    handler = handler.handler;
  }

  // 是字符串使用实例上的方法
  if (typeof handler === 'string') {
    handler = vm[key];
  }

  return vm.$watch(key, handler, options);
}


// watch 的实现就是对属性创建对应的 watcher 来监听，属性变化后就执行 watcher 中存放的回调
export function stateMixin(Vue) {
  // 这里 key 可以是属性，可以是函数
  Vue.prototype.$watch = function (key, handler, options = {}) {
    // console.log(key, handler, options)
    const vm = this;

    options.user = true;
    // 给属性添加观测器
    const watcher = new Watcher(vm, key, handler, options);

    if (options.immediate) {
      handler.call(vm, watcher.value, undefined);
    }
  }
}